function Player(params) {
  this.canvasChangeCallback = () => { // canvas元素变换时触发,参数为新的 只保留id 及class style 的新canvas元素.例如:264/265 片源切换时触发.默认是265,当源为264时会触发.触发后,传递进来的canvas需要重新获取.
    if (params.canvasChangeCallback) params.canvasChangeCallback(this.canvas);
    delete this.context;
  };

  this.onDecoder = true;
  // this.context = this.canvas.getContext("2d");
  // console.log(params);
  this.video = params.video;

  this.pauseCallback = () => { // 暂停后回调函数.无参数
    if (params.pauseCallback) params.pauseCallback();
  };
  this.resumeCallback = () => { // 恢复播放后回调函数.五参数
    if (params.resumeCallback) params.resumeCallback();
  };
  this.stopCallback = () => { // 停止播放后回调函数.无参数. 播放完毕也会回调.
    if (params.stopCallback) params.stopCallback();
  };
  this.playCallback = () => { // 开始播放后回调函数
    if (params.playCallback) params.playCallback();
  };
  this.timeChangeCallback = (t) => { // 播放画面时间点改变回调参数.每一帧回调一次.参数为当前播放时间,单位秒
    if (params.timeChangeCallback) params.timeChangeCallback(t);
  };
  this.loadedCallback = (d) => { // 视频url加载完毕后回调函数.参数为视频相关参数

    if (this.video.videoHeight) {
      this.onDecoder = false;
    }
    if ((this.videoHeight && this.video.videoHeight) || !d.v.w) {
      return;
    }
    if (!this.videoHeight) {
      this.videoWidth = this.video.videoWidth;
      this.videoHeight = this.video.videoHeight;
    }

    if (!this.canvas && this.onDecoder) {
      this.canvas = document.createElement("canvas");
      this.canvas.style["max-width"] = "100%";
      this.canvas.style["max-height"] = "100%";

      this.webglPlayer = new WebGLPlayer(this.canvas);
      this.video.parentElement.className += " ybl zc";
      this.video.parentElement.insertBefore(this.canvas, this.video);

    }

    if (!this.onDecoder) {
      this.pauseDecoder(() => {
        this.v.splice(0);
        this.a.splice(0);
      });
      this.pauseNextDecoder(() => {
        this.ca.splice(0);
        this.cv.splice(0);
      });
    }
    d.duration = this.duration;
    d.canvas = this.canvas;
    if (params.loadedCallback) params.loadedCallback(d);
    if (this.onDecoder) {
      this.canvas.width = d.v.w;
      this.canvas.height = d.v.h;
    }
  };
  this.video.onended = this.stop.bind(this);
  this.waitingCallback = (e) => { // 缓冲,暂停时回调
    if (params.waitingCallback) params.waitingCallback(e);
  };
  this.canplayCallback = (e) => { // 可以播放回调
    if (params.canplayCallback) params.canplayCallback(e);
  };
  this.playingCallback = (e) => { // 播放回调
    if (params.playingCallback) params.playingCallback(e);
  };

  let t = document.getElementsByTagName("script");
  t = t[t.length - 1].src;


  const path = params.jsLibPath ? params.jsLibPath : t.substr(0, t.lastIndexOf("/") + 1);


  if (params.decoderJsPath) {
    if (params.decoderJsPath.substr(0, 1) == ".")
      params.decoderJsPath = path + params.decoderJsPath.substr(1);
  } else params.decoderJsPath = path + "decoder.js";
  this.decoderJsPath = params.decoderJsPath;

  if (params.libJsPath) {
    if (params.libJsPath.substr(0, 1) == ".")
      params.libJsPath = path + params.libJsPath.substr(1);
  } else params.libJsPath = path + "lib.js";
  this.libJsPath = params.libJsPath;

  if (params.downloadJsPath) {
    if (params.downloadJsPath.substr(0, 1) == ".")
      params.downloadJsPath = path + params.downloadJsPath.substr(1);
  } else params.downloadJsPath = path + "downloader.js";

  this.workerDownloader = new Worker(params.downloadJsPath); // 下载线程
  this.workerDownloader.onmessage = this.downloadMsg.bind(this);
  this.first = true;
  this.ov = 0;
  this.ios = false;
  this.enableNext = true;

  this.init();
  this.displayVideo();

  this.icoL = document.getElementsByClassName("diplayer-loading-icon")[0];
  this.icoP = document.getElementsByClassName("dplayer-mobile-play")[0];
  this.setLoading = false;
  this.apf = () => {
    this.apf = null;
    this.loading(false, true);
    this.setLoading = false;
  }
  // this.displayAudio();
}
Player.prototype.init = function (currentTime) {
  this.live = false; // 直播

  if (this.pcmPlayer) {
    this.pcmPlayer.destroy();
    this.pcmPlayer = null;
  }
  this.playerState = 0; // 自身状态
  this.offsetTime = 0;
  this.currentTime = currentTime | 0;
  this.sn = 0;
  this.nextSn = 0;
  this.nextTime = 0;
  this.isDecoderCache = 0;
  this.lastTime = 0;
  this.oa = 0;
  this.tmp = 0;

  this.next = false;
  this.nextC = false;
  this.over = false;
  this.noSeek = true;

  if (this.fragments) delete this.fragments;
  this.fragments = []; // 视频文件缓冲
  if (this.a) delete this.a;
  this.a = []; // 音频数据
  if (this.v) delete this.v;
  this.v = []; // 视频数据
  if (this.ca) this.a = this.ca.splice(0);
  else this.ca = [];
  if (this.cv) this.v = this.cv.splice(0);
  else this.cv = [];
  this.downloadCallback = {};

  this.workerDecoderContinue = 0;
  this.nextWorkerDecoderContinue = 0;

  this.rz = 0;
  this.rc = 0;
  this.showLabel = document.getElementById('showLabel');
};
Player.prototype.formatTime = function (s) {
  var h = Math.floor(s / 3600) < 10 ? '0' + Math.floor(s / 3600) : Math.floor(s / 3600);
  var m = Math.floor((s / 60 % 60)) < 10 ? '0' + Math.floor((s / 60 % 60)) : Math.floor((s / 60 % 60));
  var s = Math.floor((s % 60)) < 10 ? '0' + Math.floor((s % 60)) : Math.floor((s % 60));
  return result = h + ":" + m + ":" + s;
};
Player.prototype.play = function (plC) {
  if (this.onDecoder) this.continueDecoder();
  this.lastTime = this.currentTime;
  this.playerState = 1;
  if (!plC) {
    if (this.pl) this.pl.play();
  }
  this.playCallback();
  this.noSeek = true;
};
Player.prototype.pause = function () {
  if (this.pl) {
    this.pl.pause();
  }
  if (this.onDecoder) this.pauseDecoder();
  if (this.playerState) {
    // this.playerState = 0;
    this.pauseCallback();
  }
  // this.playerState = 0;
};
Player.prototype.stop = function () {
  // this.playerState = 0;
  if (this.onDecoder) this.moveOver();
  this.currentTime = 0;
  if (this.ios) {
    this.restartAudio();
  } else {
    if (this.pl) {
      this.pl.pause();
    } else {
      // this.video.pause();
    }
  }
  this.stopCallback();
};
Player.prototype.seek = function (time, dv) {
  if (!this.videoWidth || (!this.noSeek && !dv)) return 1; // 没有初始化
  let i = this.time2i(time), j = 0;
  if (i < 0) return 2; // 时间超出
  // this.playerState = 0;
  this.noSeek = false;
  if (!dv) this.video.currentTime = this.currentTime;
  this.nextTime = this.fragments[i].end;
  if (this.onDecoder) {

    //this.pause();  // 拖动 弹出广chu告的
    this.currentTime = time;
    if (this.fragments[i].sn == this.sn) {
      this.seekTo();
    } else {
      this.sn = this.fragments[i].sn;
      if (this.nextSn == this.sn) {
        this.autoDecoder(true);
        this.seekTo();
      } else {
        this.fragments[i].offsetTime = this.currentTime;
        this.next = false;
        this.pauseDecoder(() => {
          this.a.splice(0);
          this.v.splice(0);
          this.ca.splice(0);
          this.cv.splice(0);
          if (this.ios) {
            this.nextSn = this.sn + 1;
          }
          this.sendDecoder(this.sn, () => {
            this.cachePlay = true;
            // console.log("播放");
            if (this.sn) this.play();
          });
        });
      }
    }
  }
};
Player.prototype.seekTo = function () {
  console.log("seekTo");
  this.pauseDecoder(() => {
    this.skipAudio(this.currentTime);
    this.skipVideo(this.currentTime);
    this.seekToCallback = () => {
      this.continueDecoder(() => {
        if (this.ios) this.offsetTime = this.pcmPlayer.audioCtx.currentTime - this.currentTime;
        this.cachePlay = true;
        console.log(this.sn);
        if (this.sn) this.play();
      });
    };
    this.workerDecoder.postMessage({ e: MsgDecoder.seekTo, time: this.currentTime/* , da: this.a.length ? 0 : 1 */ });


  });
};
Player.prototype.volume = function (vol) {
  // if (this.pcmPlayer) {
  //   return this.pcmPlayer.volume(this.pcmPlayer.volume() + vol);
  // }
  // console.log(this.pl);
  if (this.pl) {
    return this.pl.volume(vol);
  }
};

Player.prototype.skipAudio = function (time) {
  let i = 0, j = this.a.length - 1;
  while (i < j && this.a[i].s < time) { i++; };
  if (i) {
    this.a.splice(0, --i);
  } else {
    this.a.splice(0);
  }
};
Player.prototype.skipVideo = function (time) {
  let i = 0, j = this.v.length - 1;
  while (i < j && this.v[i].s < time) { i++ };
  if (i) {
    this.v.splice(0, --i);
  } else {
    this.v.splice(0);
  }
};
Player.prototype.displayVideo = function () {
  if (this.showLabel) {
    let t = "v:" + this.v.length;
    if (this.ios) {
      t += " a:" + parseInt(this.playerState)
    } else {
      t += " cv:" + this.cv.length
    }
    t += "<br/>n:" + parseInt(this.nextTime) + " t:" + parseInt(this.tmp);
    t += "<br/>l:" + parseInt(this.lastTime) + " c:" + parseInt(this.currentTime);
    this.showLabel.innerHTML = t;
  }
  if (this.v.length) this.tmp = this.v[0].s;
  this.currentTime = this.video.currentTime;
  if (this.onDecoder) {
    if (this.video.videoHeight) {
      this.onDecoder = false;
      this.loadedCallback({
        v: {
          w: this.video.videoWidth,
          h: this.video.videoHeight
        },
        duration: this.duration
      });
    } else {
      this.onDecoder = true;
      let t = Math.abs(this.currentTime - this.lastTime);
      if (this.playerState) {
        if (this.v.length) {
          let ti = this.currentTime - this.v[0].s - this.ov;
          if (ti >= 0) {
            this.lastTime = this.currentTime;
            if (ti < 1) {
              this.webglPlayer.renderFrame(this.v[0].d, this.videoWidth, this.videoHeight, this.yLength, this.uvLength);
              if (this.apf) this.apf();
            }
            this.v.shift();
          }
        }
      }
      if (t >= 10) {
        console.log("大于10", this.video.paused);
        if (this.created) {
          this.setLoading = true;
          this.apb = !this.video.paused;
          this.video.pause();
          this.lastTime = this.currentTime;
          this.created = false;
          this.pauseDecoder(() => {
            this.v.splice(0);
            this.nextSn = this.fragments[this.time2i(this.currentTime)].sn;
            this.autoDecoder(false, () => {
              this.playerState = 1;
              console.log(this.setLoading);
              this.setLoading = false;
              if (this.apb) {
                this.apf = () => {
                  this.loading(false, true);
                  this.video.play();
                  this.apf = undefined;
                };
              }
            });
          });
        }
      } else {
        if (this.over) {
          if (this.next && !this.v.length) this.stop();
        } else if ((this.v.length < 50 && this.next) ||
          (this.created && this.nextTime < this.currentTime)) {
          // console.log('切换', this.sn, this.next);
          if (this.nextTime < this.currentTime) this.nextSn = this.fragments[this.time2i(this.currentTime)].sn;
          this.autoDecoder();
        }
      }
      // if (this.v.length > 200 && this.workerDecoderContinue) {
      //   this.pauseDecoder();
      // } else if (this.v.length < 100 && !this.workerDecoderContinue && this.created) {
      //   this.continueDecoder();
      // }
    }
  } else {
    if (this.fragments.length) {
      delete this.fragments;
      this.fragments = []; // 视频文件缓冲
    }
    if (this.a.length) {
      delete this.a;
      this.a = []; // 音频数据
    }
    if (this.v.length) {
      delete this.v;
      this.v = []; // 视频数据
    }
    if (this.ca.length) {
      delete this.ca;
      this.ca = [];
    }
    if (this.cv.length) {
      delete this.cv;
      this.cv = []
    }
    if (this.video.videoWidth && this.video.style.display == "none") {
      // this.video.removeAttribute("");
      this.video.style.display = "";
    }
  }
  requestAnimationFrame(this.displayVideo.bind(this));
  let i = 0, j = 1, l = this.v.length;
  while (j < l) {
    if (this.v[i].s > this.v[j].s) {
      this.v.splice(i, 1);
      l--;
    } else {
      i = j;
      j++;
    }
  }

};
Player.prototype.displayAudio = function () {
  if (this.playerState && this.a.length) {
    if (this.playerState > 1) {
      console.log('加速播放');
    } else if (this.pcmPlayer) {
      let t = this.pcmPlayer.audioCtx.currentTime - this.a[0].s - this.offsetTime;
      if (Math.abs(t) > 1) {
        this.offsetTime = this.pcmPlayer.audioCtx.currentTime - this.a[0].s;
        // this.a[0].s = this.offsetTime;
        // this.offsetTime2 = this.currentTime - this.a[0].s;
      }
      // console.log(t);
      this.pcmPlayer.resume();
      let ts = this.a[0].s - this.currentTime;
      if (this.rz && Math.abs(ts) > 2) {
        this.lastTime = this.currentTime;
        this.currentTime = this.a[0].s;
        this.rz = 0;
        ts = 0;
      }
      // console.log(ts);
      if (t >= 0 && Math.abs(ts) < 3) {
        this.currentTime += this.pcmPlayer.play(this.a[0].d);
        this.timeChangeCallback(this.currentTime);
        this.a.shift();
      }
    }
  } else {
    if (this.pcmPlayer) {
      this.pcmPlayer.pause();
    }
  }
  requestAnimationFrame(this.displayAudio.bind(this));
};
Player.prototype.moveOver = function () {
  this.over = false;
  let t = this.fragments;
  this.init();
  this.fragments = t;
  this.a.splice(0);
  this.nextTime = this.fragments[1].start;
  this.v.splice(0);
  this.sn = this.time2i(this.currentTime, true);
  this.delDecoder();
  this.delNextDecoder();
  this.createDecoder(() => {
    this.sendNextDecoder(this.fragments[0].sn, () => {
      this.autoDecoder();
      this.video.currentTime = 0;
    });
  });

};
Player.prototype.downloadMsg = function (evt) {
  // console.log('下载线程回调');
  let t = 0;
  let c = 0;
  switch (evt.data.e) {
    case MsgDownloader.download:
      t = this.sn2i(evt.data.sn);
      if (t >= 0) this.fragments[t].d = evt.data.d; // 存储文件
      c = this.downloadCallback[evt.data.sn];
      delete this.downloadCallback[evt.data.sn];
      if (typeof c == "function") c(this.fragments[t]);
      break;
    case MsgDownloader.fileInfo:
      // console.log("解析", evt.data.list);
      this.useIphone(evt.data.list);
      break;
    default:
      console.warn("下载线程返回其他指令:", evt.data);
      break;
  }
};
Player.prototype.download = function (i, callback) {
  if (i < 0) return;
  this.fragments[i].e = MsgDownloader.download;
  let d = this.fragments[i];
  // delete d.url;
  d.url = this.fragments[i].url;
  if (typeof callback == "function") this.downloadCallback[this.fragments[i].sn] = callback;
  this.workerDownloader.postMessage(d); // 发送下载命令
};
Player.prototype.sureSnBuff = function (sn, callback) {
  let i = this.sn2i(sn);
  if (i < 0) {
    this.over = true;
    i = 0;
  }
  if (this.fragments[i].d) {
    if (typeof callback == "function") callback(this.fragments[i]);
  } else {
    if (this.fragments[i].e === MsgDownloader.download && this.downloadCallback[sn]) {
      if (typeof callback == "function") this.downloadCallback[sn] = callback;
    } else
      this.download(i, callback);
  }
};
Player.prototype.sendDecoder = function (sn, callback) {
  this.next = false;
  if (this.onDecoder) {
    this.sureSnBuff(sn, (a) => {
      let i = this.sn2i(sn);
      if (i < 0) {
        i = 0;
      }
      this.decoderPackCallback = (e) => {
        this.workerDecoderContinue = 0;
        if (callback) callback(e);
      };
      this.fragments[i].e = MsgDecoder.decoderPack;
      this.workerDecoder.postMessage(this.fragments[i], [this.fragments[i].d.buffer]);
      delete this.fragments[i].d;
      delete this.fragments[i].offsetTime;
    });
  }
};
Player.prototype.autoDecoder = function (pause, callback) {
  if (this.onDecoder) {
    let i = this.sn2i(this.sn);
    if (i < 0) {
      i = 0;
      this.nextSn = 0;
      this.over = true;
    }
    if (this.workerDecoder) {
      this.useNextDecoder(callback, pause, true);
    } else {
      if (i < 0) {
        this.stopCallback();
        i = 0;
        if (!this.sn) return;
      }
      this.lastTime = 0;
      this.sn = this.fragments[i].sn;
      this.sureSnBuff(this.sn, (a) => {
        this.createDecoder(() => {
          if (callback) callback();
          let fun = undefined;
          if (!pause) fun = () => {
            this.workerDecoder.postMessage({ e: MsgDecoder.continue });
          };
          this.sendDecoder(this.sn, fun);
        });
      });
      if (this.enableNext) this.createNextDecoder(true);
      else this.nextSn = this.getNext(this.sn);
    }
  }
};
Player.prototype.delDecoder = function () {
  this.created = false;
  this.workerDecoderContinue = 0;
  if (this.workerDecoder) {
    this.workerDecoder.terminate();
    delete this.workerDecoder;
  }
};
Player.prototype.createDecoder = function (callback) {
  this.created = false;
  this.delDecoder();
  this.createdCallback = () => {
    delete this.createdCallback;
    if (typeof callback == "function") callback();
  };
  this.workerDecoder = new Worker(this.decoderJsPath);
  this.workerDecoder.onmessage = this.onmessage.bind(this);

};
Player.prototype.pauseDecoder = function (callback) {
  if (this.onDecoder && this.workerDecoder) {
    this.pauseDecoderCallback = callback;
    this.workerDecoder.postMessage({ e: MsgDecoder.pause });
  }
};
Player.prototype.continueDecoder = function (callback) {
  if (this.onDecoder && this.workerDecoder) {
    this.continueDecoderCallback = callback;
    this.workerDecoder.postMessage({ e: MsgDecoder.continue });
  }
};
Player.prototype.pauseNextDecoder = function (callback) {
  if (this.onDecoder && this.enableNext) {
    this.pauseDecoderCallbackC = callback;
    this.nextWorkerDecoder.postMessage({ e: MsgDecoder.pause });
  }
};
Player.prototype.continueNextDecoder = function (callback) {
  if (this.onDecoder && this.enableNext) {
    this.continueDecoderCallbackC = callback;
    this.nextWorkerDecoder.postMessage({ e: MsgDecoder.continue });
  }
};
Player.prototype.sendNextDecoder = function (sn, callback) {
  if (this.onDecoder) {
    if (this.enableNext) {
      this.nextSn = sn;
      this.workerDecoderContinueC = 0;
      this.nextC = false;
      let fun = () => {
        this.sureSnBuff(sn, (a) => {
          let i = this.sn2i(sn);
          this.decoderPackCallbackC = callback;
          this.fragments[i].e = MsgDecoder.decoderPack;
          this.nextWorkerDecoder.postMessage(this.fragments[i], [this.fragments[i].d.buffer]);
          delete this.fragments[i].d;
          delete this.fragments[i].offsetTime;
        });
      };
      if (this.nextWorkerDecoder) {
        fun();
      } else {
        this.createNextDecoder(fun);
      }
    } else {
      this.sendDecoder(sn, callback);
    }
  }
};
Player.prototype.useNextDecoder = function (callback, pause, change) {
  if (this.onDecoder) {
    if (this.enableNext) {
      this.v = this.v.concat(this.cv.splice(0));
      this.a = this.a.concat(this.ca.splice(0));
      let workerDecoder = this.workerDecoder;
      this.sn = this.nextSn;
      this.next = this.nextC;
      // console.log(1, this.next);
      this.created = this.createdC;
      let i = this.getNext(this.sn);
      if (i < 0) { // 播放完毕
        i = 0;
        // this.stop();
        this.over = true;
      }

      this.nextSn = this.fragments[i].sn;
      this.createdC = false;
      this.nextC = false;

      this.workerDecoderContinue = this.nextWorkerDecoderContinue;
      this.nextWorkerDecoder.onmessage = this.onmessage.bind(this);
      this.workerDecoder = this.nextWorkerDecoder;
      if (typeof callback == "function") callback();
      if (change) {
        this.nextWorkerDecoder = workerDecoder;
        this.nextWorkerDecoder.onmessage = this.onmessageC.bind(this);
        if (this.createdCallback) this.createdCallback();
        this.sureSnBuff(this.nextSn, () => {
          this.fragments[i].e = MsgDecoder.decoderPack;
          this.nextWorkerDecoder.postMessage(this.fragments[i], [this.fragments[i].d.buffer]);
          delete this.fragments[i].d;
        });
        this.createdC = true;
      } else {
        workerDecoder.terminate();
        delete this.nextWorkerDecoder;
        this.createNextDecoder(true, () => {
          if (!pause) this.workerDecoder.postMessage({ e: MsgDecoder.continue });
        });
      }
      delete this.createdCallback;
    } else {
      this.created = false;
      this.next = false;
      this.sn = this.nextSn;
      let i = this.getNext(this.sn);
      if (i < 0) i = 0;
      this.nextSn = this.fragments[i].sn;
      this.sendDecoder(this.sn, (a) => {
        if (!pause) this.workerDecoder.postMessage({ e: MsgDecoder.continue });
        if (callback) callback(a);
        this.sureSnBuff(this.nextSn);
      });
    }
  }
};
Player.prototype.createNextDecoder = function (cache, callback) {
  if (this.onDecoder && this.enableNext) {
    this.createdC = false;
    this.nextWorkerDecoderContinue = 0;
    this.nextC = 0;
    this.nextSn = -1;
    if (!cache) this.createdCallbackC = () => {
      delete this.createdCallbackC;
      if (typeof callback == "function") callback(MsgDecoder.created);
    };
    this.nextWorkerDecoder = new Worker(this.decoderJsPath);
    this.nextWorkerDecoder.onmessage = this.onmessageC.bind(this);
    let i = this.getNext(this.sn);
    if (i < 0) i = 0;
    this.nextSn = this.fragments[i].sn;
    if (cache) {
      this.sureSnBuff(this.nextSn, () => {

        if (this.fragments.length > i) {
          this.fragments[i].e = MsgDecoder.decoderPack;
          this.nextWorkerDecoder.postMessage(this.fragments[i], [this.fragments[i].d.buffer]);
          delete this.fragments[i].d;
        } else {
          console.log("bug", i, this.fragments);
        }
      });
    }
  }
};
Player.prototype.delNextDecoder = function () {
  if (this.nextWorkerDecoder) {
    this.nextWorkerDecoder.terminate();
    delete this.nextWorkerDecoder;
  }
};
Player.prototype.onmessage = function (evt) {
  // console.log('解码器回调', evt.data);
  let t = 0, param = evt.data.param;
  switch (evt.data.e) {
    case MsgDecoder.videoCallback:
      this.v.push({ s: evt.data.s, d: evt.data.d });
      break;
    case MsgDecoder.audioCallback:
      this.a.push({ s: evt.data.s, d: evt.data.d });
      break;
    case MsgDecoder.decoderPack: // 解码一个ts片段
      // console.log('时间', (new Date() - this.ttm) / 1000, this.next);
      this.next = evt.data.real;
      if (!this.next) {
        this.created = true;
      }
      // console.log(2, this.next);
      if (this.decoderPackCallback) {
        t = this.decoderPackCallback;
        delete this.decoderPackCallback;
        t(evt.data, t);
      }
      break;
    case MsgDecoder.initVideo: // 初始化视频参数
      delete evt.data.e;
      switch (evt.data.a.f) {
        case 0:
          this.audioEncoding = "8bitInt";
          break;
        case 1:
          this.audioEncoding = "16bitInt";
          break;
        case 2:
          this.audioEncoding = "32bitInt";
          break;
        case 3:
          this.audioEncoding = "32bitFloat";
          break;
        default:
          this.audioEncoding = "16bitInt";
          console.warn("没有找到音频解码.默认16bitInt");
      }
      this.audioChannels = evt.data.a.c;
      this.audioSampleRate = evt.data.a.r;
      this.restartAudio();

      this.videoWidth = evt.data.v.w;
      this.videoHeight = evt.data.v.h;
      this.yLength = this.videoWidth * this.videoHeight;
      this.uvLength = (this.videoWidth / 2) * (this.videoHeight / 2);
      evt.data.duration = this.duration;
      if (!this.ov) this.ov = 0 - evt.data.v0;
      // console.log("初始化");
      this.loadedCallback(evt.data);
      break;
    case MsgDecoder.created:
      if (this.createdCallback) {
        this.createdCallback();
      }
      // if (this.a.length && this.rz) this.oa = this.currentTime - this.a[0].s;
      // console.log(this.oa);

      // this.rz = 0;

      break;
    case MsgDecoder.reload:
      // console.log('重载');
      this.rz++;
      this.workerDecoder.terminate();
      this.workerDecoder = new Worker(this.decoderJsPath);
      this.workerDecoder.onmessage = this.onmessage.bind(this);
      if (param) {
        this.createdCallback = () => {
          this.v.splice(0);
          this.a.splice(0);
          this.created = false;
          // console.log('主', param);
          delete this.createdCallback;
          this.workerDecoder.postMessage(param, [param.d.buffer]);
        };
      }
      break;
    case MsgDecoder.continue:
      this.workerDecoderContinue = 1;
      if (this.continueDecoderCallback) {
        t = this.continueDecoderCallback;
        delete this.continueDecoderCallback;
        t();
      }
      break;
    case MsgDecoder.pause:
      this.workerDecoderContinue = 0;
      if (this.pauseDecoderCallback) {
        t = this.pauseDecoderCallback;
        delete this.pauseDecoderCallback;
        t();
      }
      break;
    case MsgDecoder.fileIn:
      t = new Blob([evt.data.d], { type: "video/mp2t", name: '0.ts' });
      console.log(t, evt.data, URL.createObjectURL(t));
      break;
    case MsgDecoder.seekTo:
      if (this.seekToCallback) {
        t = this.seekToCallback;
        delete this.seekToCallback;
        t(evt.data);
      }
      break;
    default:
      console.warn("解码器其他消息", evt.data);
      break;
  }
};
Player.prototype.onmessageC = function (evt) {
  let t = 0, param = evt.data.param;
  switch (evt.data.e) {
    case MsgDecoder.videoCallback:
      this.cv.push({ s: evt.data.s, d: evt.data.d });
      break;
    case MsgDecoder.audioCallback:
      this.ca.push({ s: evt.data.s, d: evt.data.d });
      break;
    case MsgDecoder.decoderPack: // 解码一个ts片段
      // console.log('时间', (new Date() - this.ttm) / 1000);
      this.nextC = evt.data.real;
      this.threadReal = evt.data.real;
      if (this.decoderPackCallbackC) {
        t = this.decoderPackCallbackC;
        delete this.decoderPackCallbackC;
        t(evt.data, t);
      }
      break;
    case MsgDecoder.created:
      this.createdC = true;
      this.rc = 0;
      if (this.createdCallbackC) {
        this.createdCallbackC();
      }
      break;
    case MsgDecoder.initVideo:
      break;
    case MsgDecoder.reload:
      this.rc++;
      this.nextWorkerDecoder.terminate();
      this.nextWorkerDecoder = new Worker(this.decoderJsPath);
      this.nextWorkerDecoder.onmessage = this.onmessageC.bind(this);
      if (param) {
        this.cv.splice(0);
        this.ca.splice(0);
        this.createdC = false;
        this.createdCallback = () => {
          delete this.createdCallback;
          this.workerDecoder.postMessage(param, [param.d.buffer]);
        };
      }
      break;
    case MsgDecoder.continue:
      // console.log(1);
      this.nextWorkerDecoderContinue = 1;
      break;
    case MsgDecoder.pause:
      // console.log(2);
      this.nextWorkerDecoderContinue = 0;
      break;
    default:
      console.log("解码器2其他消息", evt.data);
      break;
  }
};
Player.prototype.restartAudio = function () {
  if (this.pcmPlayer) {
    this.pcmPlayer.destroy();
    delete this.pcmPlayer;
  }
  this.pcmPlayer = new PCMPlayer({
    encoding: this.audioEncoding,
    channels: this.audioChannels,
    sampleRate: this.audioSampleRate,
    flushingTime: 1000
  });

};
Player.prototype.loadSource = function (url, options, fun) {
  this.url = url;
  this.enableNext = false;
  let ua = navigator.userAgent.toLowerCase();
  if (ua.indexOf("iphone") > 0) {
    this.useIphone();
  }
  this.init();
  if (!this.pl) {
    this.pl = videojs(
      this.video.id,
      options,
      fun
    );
    this.pl.on("play", () => {
      this.play(true);
    });
    this.pl.on("pause", () => {
      this.pause();
    });
    this.pl.on("resize", () => {
      this.duration = this.pl.duration() | 0;
    });
    this.pl.on("loadedmetadata", (a, b) => { // loadeddata loadedmetadata
      if (this.video.videoWidth) {
        this.loadedCallback({
          v: {
            w: this.video.videoWidth,
            h: this.video.videoHeight
          },
          duration: this.duration
        });
      } else {
        if (this.pl.tech_.hls) {
          if (this.duration && this.onDecoder) {
            this.setVjs(this.pl.tech_.hls.playlists.media_.segments);
          }
        } else {
          this.useIphone();
        }
      }
    });
    this.pl.on("seeking", () => {
      if (this.onDecoder) this.pause();
    });
    this.pl.on("seeked", () => {
      let t = this.pl.currentTime();
      if (this.onDecoder) this.seek(t, true);
    });
    this.pl.on("timeupdate", () => {
      this.timeChangeCallback(this.currentTime);
    });
  }
  this.pl.src({
    src: url,
    type: "application/x-mpegURL",
  });
};
Player.prototype.setVjs = function (d) {
  delete this.fragments;
  this.fragments = [];
  let array = d, i, j = 0;
  for (i = 0; i < array.length; i++) {
    this.fragments.push({
      sn: i,
      url: array[i].resolvedUri,
      start: j,
      end: (j += array[i].duration),
      duration: array[i].duration
    });
  }
  i = this.time2i(this.currentTime);
  this.fragments[i].init = { fileSize: 0, listLen: 0 };

  this.sn = this.fragments[i].sn;
  this.autoDecoder();
  delete this.fragments[i].init;
  i += 2;
  if (this.fragments.length > i) this.sureSnBuff(this.fragments[i].sn);
};
Player.prototype.useHls = function () {
  if (this.hls) {
    this.hls.destroy();
    delete this.hls;
  }
  this.onDecoder = true;
  this.hls = new Hls();
  this.hls.on(Hls.Events.LEVEL_UPDATED, (e, d) => {
    if (d.details.live) {
      this.duration = 0;
    } else {
      this.duration = d.details.totalduration;
    }
    this.fragments = [];
    let array = d.details.fragments, i, j = 0;
    // console.log(array);
    for (i = 0; i < array.length; i++) {
      this.fragments.push({
        sn: i,
        url: array[i].url,
        start: j,
        end: (j += array[i].duration),
        duration: array[i].duration
      });
    }
    // console.log(this.fragments);
    i = this.time2i(this.currentTime);
    this.fragments[i].init = { fileSize: 0, listLen: 0 };
    this.sn = this.fragments[i].sn;
    this.autoDecoder(false, () => {
      this.playerState = 1;
    });
    delete this.fragments[i].init;
    i += 2;
    if (this.fragments.length > i) this.sureSnBuff(this.fragments[i].sn);
  });
  this.hls.loadSource(this.url);
  // this.hls.attachMedia(this.video);
};
Player.prototype.useIphone = function (list) {
  this.ios = navigator.userAgent.toLowerCase().indexOf("iphone") > 0;
  this.enableNext = false;
  if (list) {
    this.fragments = list;
    if (this.ios) {
      for (let i = 0; i < list.length; i++) {
        this.fragments[i].da = true;
      }
    }
    list[0].init = { fileSize: 0, listLen: 0 };
    this.sn = list[0].sn;
    this.duration = list[list.length - 1].end;
    this.autoDecoder();
    delete list[0].init;
    if (this.fragments.length > 2) this.sureSnBuff(list[0].sn);
  } else {
    // this.workerDownloader.postMessage({ e: MsgDownloader.fileInfo, url: this.url });
  }
  if (!this.pcmPlayer) {
    // this.restartAudio();
    // this.displayAudio();
  }
};
Player.prototype.useList = function (url, list) {
  this.init();
  this.enableNext = false;
  this.url = url;
  this.fragments = list;
  this.currentTime = 0;
  i = this.time2i(this.currentTime);
  this.fragments[i].init = { fileSize: 0, listLen: 0 };
  this.sn = this.fragments[i].sn;
  this.autoDecoder(false, () => {
    this.play();
    // this.v = this.delSmall(this.v);
    // console.log(this.v[0], this.v[1], this.v, this.currentTime);
  });
  delete this.fragments[i].init;
  i += 2;
  if (this.fragments.length > i) this.sureSnBuff(this.fragments[i].sn);
  this.video.onplay = () => {
    this.play();
  };
};
Player.prototype.time2i = function (time, rSn) {
  let i = 0;
  let j = this.fragments.length - 1;
  while (i < j && this.fragments[i].start < time) {
    i++;
    if (this.fragments[i].start > time) {
      i--;
      break;
    }
  }
  if (rSn) {
    if (i >= this.fragments.length) {
      i = 0;
    }
    return this.fragments[i].sn;
  }
  return i < this.fragments.length ? i : -1;
};
Player.prototype.sn2i = function (sn) {
  for (let i = 0; i < this.fragments.length; i++) {
    if (this.fragments[i].sn == sn) {
      return i;
    }
  }
  return -1;
};
Player.prototype.getNext = function (sn) {
  for (let i = 0; i < this.fragments.length; i++) {
    if (this.fragments[i].sn == sn) {
      i++;
      if (i < this.fragments.length) {
        let j = this.sn2i(this.fragments[i].sn);
        if (j < 0) {
          j = this.fragments.length;
          this.fragments.push(this.fragments[i]);
        }
        this.nextTime = this.fragments[i].start;
        return j;
      }
      break;
    }
  }
  this.over = true;
  this.nextTime = this.duration;
  return -1;
};
Player.prototype.decoderPack = function (i, callback) {
  if (i >= 0 && i < this.fragments.length) {
    // console.log("切换",this.fragments[i],this.fragments[i].e);
    this.fragments[i].offsetTime = this.seekTime;
    this.sn = this.fragments[i].sn;
    if (typeof callback == "function") this.decoderPackCallback = callback;
    if (this.fragments[i].d && this.fragments[i].d.length) {
      this.onDecoderPack(i);
    } else {
      if (this.fragments[i].e == 1) {
        let c = this.downloadCallback;
        this.downloadCallback = (r) => {
          if (c) c(r);
          this.onDecoderPack(i);
        };
      } else {
        this.download(i, () => {
          this.onDecoderPack(i);
        });
      }
    }
  }
};
Player.prototype.createCanvas = function () {
  let obj = document.createElement("canvas");
  obj.setAttribute("id", this.canvas.id);
  obj.setAttribute("class", this.canvas.className);
  obj.setAttribute("style", this.canvas.getAttribute("style"));
  // console.log(this.canvas.getAttribute("style"));
  obj.onclick = this.canvas.onclick;
  obj.width = this.videoWidth;
  obj.height = this.videoHeight;
  this.canvas.parentElement.replaceChild(obj, this.canvas);
  this.canvas = obj;
  this.canvasChangeCallback();
};
Player.prototype.fullScreen = function (el) {
  console.log(el);
  if (this.canvas.parentElement.style.transform) {
    this.exitFullScreen();
    return;
  }
  // this.canvas.parentElement.style.height = this.canvas.parentElement.parentElement.offsetWidth + "px";
  // this.canvas.parentElement.style.width = this.canvas.parentElement.parentElement.offsetHeight + "px";

  if (!el) el = this.canvas.parentElement;
  this.canvas.parentElement.style.transform = "rotate(90deg)";
  let rfs =
    el.requestFullScreen ||
    el.webkitRequestFullScreen ||
    el.mozRequestFullScreen ||
    el.msRequestFullScreen,
    obj;

  if (typeof rfs != "undefined" && rfs) {
    rfs.call(el);
    return;
  }

  if (typeof window.ActiveXObject != "undefined") {
    obj = new ActiveXObject("WScript.Shell");
    if (obj) {
      obj.SendKeys("{F11}");
    }
  }
};
Player.prototype.exitFullScreen = function () {
  let el = document;
  // var el = document,
  this.canvas.parentElement.style = "";
  let cfs =
    el.cancelFullScreen ||
    el.webkitCancelFullScreen ||
    el.mozCancelFullScreen ||
    el.exitFullScreen,
    obj;

  if (typeof cfs != "undefined" && cfs) {
    cfs.call(el);
    return;
  }
  if (typeof window.ActiveXObject != "undefined") {
    obj = new ActiveXObject("WScript.Shell");
    if (obj != null) {
      obj.SendKeys("{F11}");
    }
  }
};
Player.prototype.rotate = function (positive) {
  this.canvas.style.transform = positive ? "rotate(90deg)" : "";
};
Player.prototype.delSmall = function (params) {
  let t = false, i = 0, j = 1, l = params.length;
  while (j < l) {
    if (params[i].s > params[j].s) {
      params.splice(i, 1);
      l--;
    } else {
      i = j;
      j++;
    }
  }
  return params;
};
Player.prototype.loading = function (params, real) {
  if ((this.setLoading || real) && this.icoL) {
    if (params) {
      this.icoL.style.display = "block";
      this.icoP.style.display = "none";
    } else {
      this.icoL.style.display = null;
      this.icoP.style.display = null;
    }
  }
};
const MsgDownloader = {
  get error() { return -1; }, // 出现错误
  get fileInfo() { return 0; }, // 获取文件信息 保持与初始化一致,因为下一步就是初始化
  get download() { return 1; }, // 下载文件
  get dataIn() { return 2; }, // 数据到达
};
const MsgDecoder = {
  get error() { return -1; }, // 出现错误
  get initDecoder() { return 0 }, // 解码器已初始化 尽可能与下载文件一致.减少写数据
  get uninitDecoder() { return -10002 }, // 解码器已卸载
  get openDecoder() { return -10003 }, // 打开解码器
  get closeDecoder() { return -10004 }, // 关闭解码器
  get startDecoding() { return -10005 }, // 解码操作
  get audioCallback() { return -10006 }, // 音频数据
  get videoCallback() { return -10007 }, // 视频数据
  get requestCallback() { return -10008 }, // 请求数据
  get seekTo() { return -10009 }, // 跳转时间
  get sendData() { return -10010 }, // 发送数据
  get simpleDecode() { return -10011 }, // 简易解码 包含初始化等一键式解码
  get testApi() { return -10012 }, // 
  get offsetTime() { return -10013 }, // 
  get decoderOnePacket() { return -10014 }, // 
  get decoderPack() { return -10015 }, // 
  get initVideo() { return -10016 }, // 
  get created() { return -10017 }, // 
  get reload() { return -10018 }, // 
  get continue() { return -10019 }, // 
  get pause() { return -10020 }, // 
  get setOffsetTime() { return -10021 }, // 
  get fileIn() { return -10022 }, // 解码器已卸载
};
